import { buffer, util } from "@kit.ArkTS";
import { socket } from "@kit.NetworkKit";
import { Sink } from "./Sink";
import { IOException, SocketTimeoutException } from "../Error/error";

// import { Sink } from "./Sink";

/**
 * 基于 ArrayBuffer 的缓冲写入流
 */
export class BufferedSink implements Sink{
  private buf: ArrayBuffer;
  private view: Uint8Array;
  private pos: number = 0;
  rawSocket: socket.TCPSocket = null;
  sslSocket: socket.TLSSocket = null;
  // private isClosed: boolean = false;

  /**
   * 构造函数
   * @param socket - 已连接的 Socket 实例
   * @param capacity - 缓冲区大小（字节），默认 8192
   */
  constructor(rawSocket?: socket.TCPSocket, sslSocket?: socket.TLSSocket, capacity: number = 8192) {
    this.rawSocket = rawSocket
    this.sslSocket = sslSocket
    this.buf = new ArrayBuffer(capacity);
    this.view = new Uint8Array(this.buf);
  }

  buffer(): Sink {
    return this;
  }

  /**
   * 将数据写入缓冲区
   * @param data Uint8Array 或 string
   * @throws 如果数据超出缓冲区剩余空间
   */
  async write(data: Uint8Array | string, byteCount?: number) {
    // if (this.isClosed) {
    //   throw new Error('BufferedSocketSink is closed');
    // }

    // 转换为 Uint8Array
    let chunk: Uint8Array;
    if (typeof data === 'string') {
      chunk = new util.TextEncoder().encodeInto(data);
    } else {
      chunk = data;
    }
    let offset = 0; // 当前 chunk 的读取偏移

    while (offset < chunk.length) {
      const available = this.capacity - this.pos; // 剩余空间
      const toWrite = Math.min(available, chunk.length - offset); // 本次能写多少

      if (toWrite === 0) {
        // 缓冲区已满，必须 flush
        await this.flush();
        // flush 后 pos 已重置为 0，available 自动变大
        continue;
      }

      // 写入最多 toWrite 字节
      this.view.set(chunk.subarray(offset, offset + toWrite), this.pos);
      this.pos += toWrite;
      offset += toWrite;

      // 可选：如果缓冲区满了，立即 flush（避免下次还要判断）
      if (this.isFull) {
        await this.flush();
      }
    }
  }

  /**
   * 扩容缓冲区，确保至少能容纳 newLength 字节
   * 策略：新容量 = max(当前容量 * 2, newLength)
   * @param newLength 所需最小长度
   */
  private expandBuffer(newLength: number): void {
    // 计算新容量：至少翻倍，或满足需求
    let newCapacity = this.buf.byteLength > 0 ? this.buf.byteLength : 8192; // 初始容量
    while (newCapacity < newLength) {
      newCapacity *= 2;
    }

    // 创建新缓冲区
    const newBuf = new ArrayBuffer(newCapacity);
    const newView = new Uint8Array(newBuf);

    // 复制旧数据
    if (this.pos > 0) {
      newView.set(this.view.subarray(0, this.pos), 0);
    }

    // 切换到新缓冲区
    this.buf = newBuf;
    this.view = newView;

    // 可选：打印日志（调试用）
    // console.log(`Buffer expanded: ${this.buf.byteLength} -> ${newCapacity}`);
  }

  /**
   * 将缓冲区中所有数据通过 Socket 发送
   * 发送后清空缓冲区（重置 pos）
   */
  async flush() {
    if (this.pos === 0) { // this.isClosed ||
      return;
    }
    let offset = this.pos
    try{
      // 创建一个仅包含有效数据的 Uint8Array 视图
      if (this.rawSocket === null || this.rawSocket === undefined){
        console.log("testzhf request::",buffer.from(this.buf.slice(0, this.pos)).toString())
        await this.sslSocket.send(this.buf.slice(0, offset))
        this.pos = 0
      }else{
        console.log("testzhf request::",buffer.from(this.buf.slice(0, this.pos)).toString())
        await this.rawSocket.send({data: this.buf.slice(0, offset)})
        this.pos = 0
      }
    }catch (e) {
      // 将错误转换为 IOException 以便重试机制能正确处理
      console.error("okhttp :: BufferedSink.flush error:", JSON.stringify(e))
      if (e instanceof IOException || e instanceof SocketTimeoutException) {
        throw e
      }
      const errorMessage = (e instanceof Error) ? e.message : String(e)
      throw new IOException(`Failed to send data: ${errorMessage}`)
    }
  }

  /**
   * 关闭 Sink，禁止进一步写入
   * 自动调用 flush()
   */
  async close() {
    // if (this.isClosed) {
    //   return;
    // }
    // this.isClosed = true;
    await this.flush(); // 确保最后的数据被发送
  }

  /**
   * 获取当前缓冲区使用量
   */
  get usedSize(): number {
    return this.pos;
  }

  /**
   * 获取缓冲区总容量
   */
  get capacity(): number {
    return this.view.byteLength;
  }

  /**
   * 是否已满
   */
  get isFull(): boolean {
    return this.pos >= this.capacity;
  }

  /**
   * 是否为空
   */
  get isEmpty(): boolean {
    return this.pos === 0;
  }
}

